<template>
   <section
    :style="{ ...styles.box, ...boxStyle }"
    class="v-screen-box"
    ref="box"
  >
    <div
      :style="{ ...styles.wrapper, ...wrapperStyle }"
      class="screen-wrapper"
      ref="screenWrapper"
    >
      <slot></slot>
    </div>
  </section>
</template>

<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
import type { CSSProperties, PropType } from "vue";
import { resolve } from "dns";

interface IState {
  originalWidth: string | number;
  originalHeight: string | number;
  width?: string | number;
  height?: string | number;
  observer: null | MutationObserver;
}
type IAutoScale =
  | boolean
  | {
      x?: boolean;
      y?: boolean;
    };

const props = defineProps({
  width: {
    type: [String, Number] as PropType<string | number>,
    default: 1920,
  },
  height: {
    type: [String, Number] as PropType<string | number>,
    default: 1080,
  },
  fullScreen: {
    type: Boolean as PropType<boolean>,
    default: false,
  },
  autoScale: {
    type: [Object, Boolean] as PropType<IAutoScale>,
    default: true,
  },
  delay: {
    type: Number as PropType<number>,
    default: 500,
  },
  boxStyle: {
    type: Object as PropType<CSSProperties>,
    default: () => ({}),
  },
  wrapperStyle: {
    type: Object as PropType<CSSProperties>,
    default: () => ({}),
  },
});

const state = ref<IState>({
    width:0,
    height:0,
    originalHeight:0,
    originalWidth:0,
    observer:null
})
const screenWrapper = ref<HTMLElement>();
const box = ref<HTMLElement>();

const styles:Record<string,CSSProperties> ={
    box:{
        overflow:'hidden',
        background:'#000',
        backgroundSize:'100% 100%',
        width:'100vw',
        height:'100vh'
    },
    wrapper:{
        transitionProperty:'all',
        transitionTimingFunction:`cubic-bezier(0.4,0,0.2,1)`,
        transitionDuration: `500ms`,
        position: `relative`,
        overflow: `hidden`,
        zIndex: 100,
        transformOrigin: `left top`,
    }
} 

onMounted(() => {
  nextTick(async () => {
    await initSize();
    updateSize();
    updateScale();
    addListener();
    console.log(1111);
    
    // initMutationObserver();
  });
});

watch(()=>props.autoScale,(newValue)=>{
    if(newValue){
        onResize();
        addListener();
    }else{
        clearListener();
        clearScreenWrapperStyle();
    }
})

/**
 * 初始化大屏
 */
function initSize(){
    return new Promise<void>((resolve) =>{
        box.value!.scrollLeft =0;
        box.value!.scrollTop =0;
        nextTick(()=>{
            // region 获取大屏幕真实尺寸
            if(props.width && props.height){
                state.value.width = props.width
                state.value.height = props.height
            }else{
                state.value.width = screenWrapper.value?.clientWidth
                state.value.height = screenWrapper.value?.clientHeight
            }
            // region 获取画布尺寸
            if(!state.value.originalHeight || !state.value.originalWidth){
                state.value.originalWidth = window.screen.width;
                state.value.originalHeight =window.screen.height
            }
            resolve()
        })
    })
}

/**
 * 更新大屏尺寸
 */
const updateSize = ()=>{
    if(state.value.width && state.value.height){
        screenWrapper.value!.style.width = `${state.value.width}px`
        screenWrapper.value!.style.height = `${state.value.height}px`
    }else{
        screenWrapper.value!.style.width = `${state.value.originalWidth}px`;
        screenWrapper.value!.style.height = `${state.value.originalHeight}px`;
    }
}

function clearScreenWrapperStyle(){
    screenWrapper.value!.style.transform =""
    screenWrapper.value!.style.margin =""
}
/**
 * 防抖函数
 * @param fn 防抖主体
 * @param delay 时间
 */
function debounce(fn:Function,delay:number){
    let timer:any
    return function(...args:any[]):void{
        if(timer) clearTimeout(timer)
        timer =setTimeout(() => {
            typeof fn === 'function' && fn.apply(null,args)
        }, delay > 0 ? delay : 100);
    }
}

/**
 * 自适应缩放
 * @param scale 
 */
function autoScale(scale: any){
    if(!props.autoScale){
        return
    }
    const domWidth = screenWrapper.value!.clientWidth
    const domHeight = screenWrapper.value!.clientHeight
    const currentWidth = document.body.clientWidth
    const currentHeight = document.body.clientHeight

    screenWrapper.value!.style.transform = `scale(${scale},${scale})`

    let mx = Math.max((currentWidth - domWidth*scale)/2,0)
    let my = Math.max((currentHeight- domHeight*scale)/2,0)

    if(typeof props.autoScale === 'object'){
        !props.autoScale.x && (mx =0)
        !props.autoScale.y && (my =0)
    }
    screenWrapper.value!.style.margin = `${my}px ${mx}px`
}

/**
 * 更新自动缩放
 */
function updateScale(){
    // 获取真实视口尺寸
  const currentWidth = document.body.clientWidth;
  const currentHeight = document.body.clientHeight;
  // 获取大屏最终的宽高
  const realWidth = state.value.width || state.value.originalWidth;
  const realHeight = state.value.height || state.value.originalHeight;
  // 计算缩放比例
  const widthScale = currentWidth / +realWidth;
  const heightScale = currentHeight / +realHeight;
   // 若要铺满全屏，则按照各自比例缩放
   if (props.fullScreen) {
    screenWrapper.value!.style.transform = `scale(${widthScale},${heightScale})`;
    return false;
  }
   // 按照宽高最小比例进行缩放
   const scale = Math.min(widthScale, heightScale);
  autoScale(scale);
}

const onResize = debounce(async()=>{
    await initSize();
    updateSize()
    updateScale()
},props.delay)


const initMutationObserver=()=>{
    const observer =  (state.value.observer = new MutationObserver(()=>{
        onResize()
    }))
    observer.observe(screenWrapper.value!,{
        attributes:true,
        attributeFilter:['steyle'],
        attributeOldValue:true
    })
}
/**
 * 清除监听事件
 */
const clearListener = () => {
  window.removeEventListener("resize", onResize);
  // state.observer?.disconnect();
};
/**
 * 增加监听事件
 */
const addListener = () => {
  window.addEventListener("resize", onResize);
  // initMutationObserver();
};
onUnmounted(() => {
  clearListener();
  // state.observer?.disconnect();
});
</script>

<style lang="scss" scoped>

</style>